home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / AlertFakeLib / AlertFakeLib.c next >
Encoding:
C/C++ Source or Header  |  1993-12-17  |  12.8 KB  |  491 lines  |  [TEXT/KAHL]

  1. /* Functions for creating and displaying an alert which is not read in
  2.     from a resource, and is therefore called a "fake" alert. This is most
  3.     useful for reporting Resource Manager errors. The total dynamic heap
  4.     memory needed to display the alert is fairly small since most of the
  5.     data structures are allocated on the stack or in static memory.
  6.     
  7.     Since the alert is to be displayed in response to a Resource Manager
  8.     error, it wouldn't make sense to try to read the error strings in
  9.     from the resource file. Therefore, there are a few hard-coded strings
  10.     in this file, such as the titles of the ok and cancel buttons, and the
  11.     basic string for a Resource Manager error.
  12.     
  13.     This file makes calls only to the Macintosh Toolbox. It does not call
  14.     any private libraries or any of the standard C libraries. It only
  15.     requires that TEInit has been called and it requires a minimal amount
  16.     of memory to create and display a window containing an alert message.
  17.     
  18.     Revision History:
  19.     
  20.     93/12/15 aih
  21.     - fixed error in calculation of bottom of text rectangle
  22.     
  23.     93/11/22 aih
  24.     - Only Pascal strings are used, so I don't need any C to Pascal conversion
  25.     functions
  26.     - Removed all uses of the ANSI library, so that this library is not
  27.     depended on code other than the what was available in the 64K ROMs.
  28.     
  29.     93/11/13 aih
  30.     - ShowHide is used instead of ShowWindow/HideWindow so activate/deactivate
  31.     events aren't generated
  32.     
  33.     93/10/25 aih
  34.     - made alert bigger
  35.     - made first button's position relative to window's lower right corner,
  36.     instead of hard-coding the coordinates
  37.     
  38.     93/10/19 AIH
  39.     - Expanded a few comments
  40.     
  41.     93/03/23 AIH
  42.     - Removed use of MathLib.c and MacLib.c, since those
  43.     files could be in a different segment
  44.     
  45.     93/03/19 AIH
  46.     - Added AlertFakeOSErr
  47.     - Changed AlertFakeLibBegin to AlertFakeInit
  48.     
  49.     93/03/13 AIH
  50.     - Moved private defines from header into this file
  51.     
  52.     91/05/06 AIH
  53.     - Fixed bug with icon plotting if ResLoad was false
  54.     
  55.     91/04/24 AIH
  56.     - Added function to reset the alert after it has been run; this is
  57.     needed for the preloaded alert
  58.     
  59.     91/04/22 AIH
  60.     - Removed dependence on things available only in "newer" system software;
  61.     it's my guess that the functions in this file will work correctly even
  62.     with very old system software
  63.     
  64.     91/04/17 AIH
  65.     - The alert's port isn't set after NewWindow is called
  66.     
  67.     91/04/10 AIH
  68.     - Alerts can be preloaded
  69.     
  70.     91/03/24 AIH
  71.     - Adapted to use key library function for international canceling
  72.     
  73.     91/03/23 AIH
  74.     - Updated a few of the comments.
  75.     
  76.     91/03/02 AIH
  77.     - Update events are only handled if they apply to the alert's window
  78.     
  79.     91/02/28 AIH
  80.     - Call event library instead of WNE
  81.     
  82.     91/02/08 AIH
  83.     - Storage for alert is allocated on stack instead of statically
  84.     
  85.     91/01/21 Ari Halberstadt (AIH)
  86.     - Created this library to report resource manager errors, especially
  87.     resource manager errors in the Dialog Manager. */
  88.      
  89. #include <stdarg.h>
  90. #include "AlertFakeLib.h"
  91.  
  92. /* maximum number of buttons */
  93. #define ALERT_MAXBUTTON    (3)
  94.  
  95. /* parameters for setting the position and size of the alert */
  96. #define MARGIN                (8)
  97. #define ALERT_TOP            (0)
  98. #define ALERT_LEFT        (0)
  99. #define ALERT_WIDTH        (72 * 5)
  100. #define ALERT_HEIGHT        (72 * 2)
  101. #define BUTTON_WIDTH        (72)
  102. #define BUTTON_HEIGHT     (20)
  103. #define BUTTON_TOP        (ALERT_HEIGHT - BUTTON_HEIGHT - MARGIN)
  104. #define BUTTON_LEFT        (ALERT_WIDTH - BUTTON_WIDTH - MARGIN)
  105. #define ICON_TOP            (10)
  106. #define ICON_LEFT            (20)
  107. #define ICON_WIDTH        (32)
  108. #define ICON_HEIGHT        (32)
  109. #define TEXT_TOP            (ALERT_TOP + MARGIN)
  110. #define TEXT_LEFT            (ICON_LEFT + ICON_WIDTH + 20)
  111. #define TEXT_BOTTOM        (BUTTON_TOP - MARGIN)
  112. #define TEXT_RIGHT        (ALERT_WIDTH - MARGIN)
  113.  
  114. typedef struct {
  115.     WindowRecord        windowRec;    /* storage for the window */
  116.     WindowPtr            window;        /* pointer to the window */
  117.     Rect                    windowRect;    /* window's rectangle */
  118.     Rect                    textRect;    /* text's rectangle */
  119.     Rect                    iconRect;    /* icon's rectangle */
  120.     short                    iconid;        /* resource id of icon */
  121.     short                    okbut;        /* ok button */
  122.     short                    cancelbut;    /* cancel button */
  123.     short                    clicked;        /* button clicked */
  124.     short                    nbuttons;    /* number of buttons */
  125.     StringPtr            text;            /* text displayed */
  126.     ControlHandle        button[ALERT_MAXBUTTON];    /* list of buttons */
  127. } AlertFakeType;
  128.  
  129. /* strings that aren't read from resources */
  130. #define TEXT_OK        ((StringPtr) "\pOK")
  131. #define TEXT_CANCEL    ((StringPtr) "\pCancel")
  132. #define TEXT_OSERR    ((StringPtr) "\pError #%d occurred.")
  133. #define TEXT_RES        ((StringPtr) "\pCould not get a resource (error #%d).")
  134. #define TEXT_MEM        ((StringPtr) "\pOut of memory.")
  135. #define TEXT_FAILED    ((StringPtr) "\pCould not complete the operation.")
  136.  
  137. /* the alert that's created when the library is initialized */
  138. static AlertFakeType gAlertOk;
  139.  
  140. /* a handle used for formatting text strings for display */
  141. static Handle gTextHandle;
  142.  
  143. /* fill with nulls */
  144. static void memzap(void *p, long n)
  145. {
  146.     char *q = p;
  147.     while (n-- > 0) *q++ = 0;
  148. }
  149.  
  150. /* position the rectangle within the main screen */
  151. static void PositionInScreen(Rect *r)
  152. {
  153.     Rect scrn;
  154.     Point pos;
  155.     SysEnvRec world;
  156.  
  157.     scrn = screenBits.bounds;
  158.     (void) SysEnvirons(curSysEnvVers, &world);
  159.     scrn.top += ((world.systemVersion >= 0x0410) ? GetMBarHeight() : 20);
  160.     pos.h = scrn.left + ((scrn.right - scrn.left) - (r->right - r->left)) / 2;
  161.     pos.v = scrn.top + ((scrn.bottom - scrn.top) - (r->bottom - r->top)) / 3;
  162.     OffsetRect(r, pos.h - r->left, pos.v - r->top);
  163. }
  164.  
  165. /* draw the alert's buttons */
  166. static void AlertFakeDrawButtons(AlertFakeType *alrt)
  167. {
  168.     DrawControls(alrt->window);
  169. }
  170.  
  171. /* draw the text of the alert */
  172. static void AlertFakeDrawText(AlertFakeType *alrt)
  173. {
  174.     GrafPtr port;
  175.         
  176.     GetPort(&port);
  177.     SetPort(alrt->window);
  178.     if (alrt->text)
  179.         TextBox(alrt->text + 1, *alrt->text, &alrt->textRect, teJustLeft);
  180.     else
  181.         EraseRect(&alrt->textRect);
  182.     SetPort(port);
  183. }
  184.  
  185. /* draw the alert's icon */
  186. static void AlertFakeDrawIcon(AlertFakeType *alrt)
  187. {
  188.     GrafPtr    port;
  189.     Handle    icon;
  190.     
  191.     GetPort(&port);
  192.     SetPort(alrt->window);
  193.     icon = GetIcon(alrt->iconid);
  194.     if (icon && *icon)
  195.         PlotIcon(&alrt->iconRect, icon);
  196.     SetPort(port);
  197. }
  198.  
  199. /* draw the alert */
  200. static void AlertFakeDraw(AlertFakeType *alrt)
  201. {
  202.     AlertFakeDrawButtons(alrt);
  203.     AlertFakeDrawText(alrt);
  204.     AlertFakeDrawIcon(alrt);
  205. }
  206.  
  207. /* return item clicked in alert */
  208. static short AlertFakeClicked(AlertFakeType *alrt)
  209. {
  210.     return(alrt->clicked);
  211. }
  212.  
  213. /* make the alert visible */
  214. static void AlertFakeShow(AlertFakeType *alrt)
  215. {
  216.     InitCursor();
  217.     FlushEvents(everyEvent, 0);
  218.     BringToFront(alrt->window);
  219.     HiliteWindow(alrt->window, true);
  220.     ShowHide(alrt->window, true);
  221.     SysBeep(5);
  222. }
  223.  
  224. /* make the alert invisible */
  225. static void AlertFakeHide(AlertFakeType *alrt)
  226. {
  227.     ShowHide(alrt->window, false);
  228.     FlushEvents(everyEvent, 0);
  229. }
  230.  
  231. /* add button to alert */
  232. static void AlertFakeButton(AlertFakeType *alrt, const StringPtr title)
  233. {
  234.     Rect bounds;
  235.     short width = 0;
  236.     ControlHandle button = NULL;
  237.     
  238.     if (alrt->nbuttons < ALERT_MAXBUTTON) {
  239.         if (alrt->nbuttons > 0) {
  240.             bounds = (**alrt->button[alrt->nbuttons-1]).contrlRect;
  241.             bounds.right = bounds.left - 16;
  242.         }
  243.         else {
  244.             SetRect(&bounds, BUTTON_LEFT, BUTTON_TOP,
  245.                 BUTTON_LEFT + BUTTON_WIDTH, BUTTON_TOP + BUTTON_HEIGHT);
  246.         }
  247.         button = NewControl(alrt->window, &bounds, title, true, 0, 0, 1,
  248.                                     pushButProc, 0);
  249.         if (button)
  250.             alrt->button[alrt->nbuttons++] = button;
  251.     }
  252. }
  253.  
  254. /* set alert's icon */
  255. static void AlertFakeIcon(AlertFakeType *alrt, short iconid)
  256. {
  257.     alrt->iconid = iconid;
  258.     AlertFakeDrawIcon(alrt);
  259. }
  260.  
  261. /* set alert's text */
  262. static void AlertFakeText(AlertFakeType *alrt, const StringPtr text)
  263. {
  264.     alrt->text = (StringPtr) text;
  265.     AlertFakeDrawText(alrt);
  266. }
  267.  
  268. /* handle a click in the alert at the given point */
  269. static void AlertFakeClick(AlertFakeType *alrt, Point pt)
  270. {
  271.     ControlHandle    button;    /* button clicked */
  272.     short                part;        /* part of control where event occurred */
  273.     short                i;            /* index to buttons */
  274.     
  275.     part = FindControl(pt, alrt->window, &button);
  276.     if (part == inButton && TrackControl(button, pt, 0L) == inButton) {
  277.         for (i = 0; i < alrt->nbuttons && alrt->button[i] != button; i++)
  278.             ;
  279.         if (i < alrt->nbuttons)
  280.             alrt->clicked = i + 1;
  281.     }
  282. }
  283.  
  284. /* handle a single event in the alert */
  285. static void AlertFakeEvent(AlertFakeType *alrt, EventRecord *event)
  286. {
  287.     short                where;    /* where mouse was clicked */
  288.     WindowPtr        window;    /* window in which mouse was clicked */
  289.     ControlHandle    control;    /* control in which mouse was clicked */
  290.     Point                pt;        /* where event occurred in local coordinates */
  291.     GrafPtr            port;        /* saved port */
  292.     unsigned char    key;        /* key hit by user */
  293.     
  294.     /* set port to alert's window */
  295.     GetPort(&port);
  296.     SetPort(alrt->window);
  297.     
  298.     /* handle the event */
  299.     switch (event->what) {
  300.     case mouseDown:
  301.         /* handle a click in the button */
  302.         where = FindWindow(event->where, &window);
  303.         if (where == inContent && window == alrt->window) {        
  304.             pt = event->where;
  305.             GlobalToLocal(&pt);
  306.             AlertFakeClick(alrt, pt);    
  307.         }
  308.         else
  309.             SysBeep(5);
  310.         break;
  311.         
  312.     case updateEvt:
  313.         if ((WindowPtr)event->message == alrt->window) {
  314.             BeginUpdate(alrt->window);
  315.             AlertFakeDraw(alrt);
  316.             EndUpdate(alrt->window);
  317.         }
  318.         break;
  319.     }
  320.     
  321.     /* restore port */
  322.     SetPort(port);
  323. }
  324.  
  325. /* handle events in the alert */
  326. static void AlertFakeRun(AlertFakeType *alrt)
  327. {
  328.     EventRecord event;
  329.     
  330.     /* wait for user to click a button */
  331.     while (! AlertFakeClicked(alrt)) {
  332.         if (GetNextEvent(everyEvent, &event))
  333.             AlertFakeEvent(alrt, &event);
  334.     }
  335. }
  336.  
  337. /* reset the alert */
  338. static void AlertFakeReset(AlertFakeType *alrt)
  339. {
  340.     alrt->clicked = 0;
  341. }
  342.  
  343. /* setup the alert */
  344. static void AlertFakeBegin(AlertFakeType *alrt)
  345. {
  346.     GrafPtr port = NULL;
  347.     
  348.     /* clear everything */
  349.     memzap(alrt, sizeof(AlertFakeType));
  350.     
  351.     /* set up rectangles */
  352.     SetRect(&alrt->windowRect, ALERT_LEFT, ALERT_TOP,
  353.         ALERT_LEFT + ALERT_WIDTH, ALERT_TOP + ALERT_HEIGHT);
  354.     SetRect(&alrt->textRect, TEXT_LEFT, TEXT_TOP,
  355.         TEXT_RIGHT, TEXT_BOTTOM);
  356.     SetRect(&alrt->iconRect, ICON_LEFT, ICON_TOP,
  357.         ICON_LEFT + ICON_WIDTH, ICON_TOP + ICON_HEIGHT);
  358.     
  359.     /* set buttons */
  360.     alrt->okbut = ok;
  361.     alrt->cancelbut = cancel;
  362.     
  363.     /* create window */
  364.     GetPort(&port);
  365.     alrt->window = (WindowPtr) &alrt->windowRec;
  366.     PositionInScreen(&alrt->windowRect);
  367.     NewWindow((WindowPeek) alrt->window, &alrt->windowRect,
  368.                 (StringPtr) "\pAlert", false, dBoxProc, (WindowPtr) -1L, false, 0L);
  369.     SetPort(alrt->window);
  370.     TextFont(systemFont);
  371.     SetPort(port);
  372. }
  373.  
  374. /* end the alert */
  375. static void AlertFakeEnd(AlertFakeType *alrt)
  376. {
  377.     while (alrt->nbuttons > 0)
  378.         DisposeControl(alrt->button[--alrt->nbuttons]);
  379.     CloseWindow(alrt->window);
  380.     alrt->window = NULL;
  381. }
  382.  
  383. /* Setup and run a generic alert. */
  384. short AlertFakeGeneric(const StringPtr text, short iconid, short count, ...)
  385. {
  386.     AlertFakeType alrt;
  387.     va_list ap;
  388.     short result = 0;
  389.  
  390.     AlertFakeBegin(&alrt);
  391.     AlertFakeText(&alrt, text);
  392.     AlertFakeIcon(&alrt, stopIcon);
  393.     va_start(ap, count);
  394.     while (count-- > 0)
  395.         AlertFakeButton(&alrt, va_arg(ap, StringPtr));
  396.     va_end(ap);
  397.     AlertFakeShow(&alrt);
  398.     AlertFakeRun(&alrt);
  399.     result = AlertFakeClicked(&alrt);
  400.     AlertFakeEnd(&alrt);
  401.     return(result);
  402. }
  403.  
  404. /* display an alert with an ok button */
  405. void AlertFakeOk(const StringPtr text, short icon)
  406. {
  407.     static Boolean using;
  408.     
  409.     /* see if we can use the preloaded alert */
  410.     if (gAlertOk.window && ! using) {
  411.         using = true;
  412.         AlertFakeText(&gAlertOk, text);
  413.         AlertFakeIcon(&gAlertOk, icon);
  414.         AlertFakeShow(&gAlertOk);
  415.         AlertFakeRun(&gAlertOk);
  416.         AlertFakeHide(&gAlertOk);
  417.         AlertFakeReset(&gAlertOk);
  418.         using = false;
  419.     }
  420.     else /* it wasn't created or it's already in use so create a new alert */
  421.         AlertFakeGeneric(text, icon, 1, TEXT_OK);
  422. }
  423.  
  424. /* display an alert with ok and cancel buttons */
  425. Boolean AlertFakeOkCancel(const StringPtr text, short icon)
  426. {
  427.     return(AlertFakeGeneric(text, icon, 2, TEXT_OK, TEXT_CANCEL) == ok);
  428. }
  429.  
  430. /* display an alert for an error number */
  431. static void AlertFakeErr(OSErr err, const StringPtr format)
  432. {
  433.     Handle text = gTextHandle;
  434.     Str31 num;
  435.     
  436.     if (text) {
  437.         SetHandleSize(text, *format + 1);
  438.         if (MemError() == noErr) {
  439.             NumToString(err, num);
  440.             BlockMove(format, *text, *format + 1);
  441.             Munger(text, 1, "%d", 2, num+1, *num);
  442.             **text = GetHandleSize(text) - 1;
  443.             MoveHHi(text);
  444.             HLock(text);
  445.             AlertFakeOk((StringPtr) *text, stopIcon);
  446.             HUnlock(text);
  447.             SetHandleSize(text, sizeof(Str255));
  448.         }
  449.     }
  450. }
  451.  
  452. /* display an alert for a failed exception */
  453. void AlertFakeFailed(OSErr err, const StringPtr text)
  454. {
  455.     if (err)
  456.         AlertFakeOSErr(err);
  457.     else if (text && *text)
  458.         AlertFakeOk(text, stopIcon);
  459.     else
  460.         AlertFakeOk(TEXT_FAILED, stopIcon);
  461. }
  462.  
  463. /* display an alert for an operating system error */
  464. void AlertFakeOSErr(OSErr err)
  465. {
  466.     AlertFakeErr(err, TEXT_OSERR);
  467. }
  468.  
  469. /* display an alert for a resource error */
  470. void AlertFakeRes(OSErr err)
  471. {
  472.     AlertFakeErr(err, TEXT_RES);
  473. }
  474.  
  475. /* display an alert for a low memory situation; there should be enough
  476.     memory to show the window, or this may crash */
  477. void AlertFakeMem(void)
  478. {
  479.     AlertFakeOk(TEXT_MEM, cautionIcon);
  480. }
  481.  
  482. /* initialize the fake alert library by pre-creating a fake alert */
  483. void AlertFakeInit(void)
  484. {
  485.     if (! gTextHandle) {
  486.         AlertFakeBegin(&gAlertOk);
  487.         AlertFakeButton(&gAlertOk, TEXT_OK);
  488.         gTextHandle = NewHandle(sizeof(Str255));
  489.     }
  490. }
  491.